#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>

#include "./CLI_ENGINE/vector.h"
#include "./CLI_ENGINE/vty.h"
#include "./CLI_ENGINE/zebra.h"
#include "./CLI_ENGINE/thread.h"
#include "./CLI_ENGINE/zserv.h"
#include "./CLI_ENGINE/command.h"
#include "./CLI_ENGINE/config.h"

#include "./CLI_COMMANDS/GENERAL_COMMAND/general_commands.h"
#include "./CLI_COMMANDS/LOG_COMMAND/log_commands.h"
#include "./CLI_COMMANDS/SWITCH_COMMAND/switch_commands.h"

#include "cli_start.h"
#include "../Platform/COMMON/typedef.h"
#include "../config.h"
#include "../Log/ZLOG/src/zlog.h"
#ifdef __EXTERNAL_LOGIN__
	#include <termios.h>
#endif


#define __MODULE__ "CLI"

extern vector vtyvec;
extern bool PMC_kill_all_vty;
struct thread_master *master;
struct thread *global_thread;
struct zebra_t zebrad = {0, 0, 0};

static unsigned short int alternative_port = 0;

#ifdef __EXTERNAL_LOGIN__
static int uart_set_proper(INT32U fd, INT32U baud, INT32U databits, INT32U stopbits, INT32U parity)
{
        struct termios options, oldoptions;
	int tc_ret = 0;

	 tc_ret = tcgetattr(fd, &oldoptions);
        if(tc_ret != 0)
        {
                perror("set_proper");
                return(1);
        }

        bzero(&options, sizeof(options));
        options.c_cflag  |=  CLOCAL | CREAD;
        options.c_cflag &= ~CSIZE;
        switch (databits)
        {
                case 7:
                        	options.c_cflag |= CS7; break;
                case 8:
                        	options.c_cflag |= CS8; break;
                default:
                       	fprintf(stderr,"Unsupported data bit !\n");
                        	return (1);
        }
        switch (parity)
        {
                case 'n':
                case 'N':
                        	options.c_cflag &= ~PARENB;
                        	options.c_iflag &= ~INPCK;
                        	break;

                case 'o':
                case 'O':
                        	options.c_cflag |= PARENB;
                        	options.c_cflag |= PARODD;
                        	options.c_iflag |= (INPCK | ISTRIP);
                        	break;
                case 'e':
                case 'E':
	                      options.c_cflag |= PARENB;
	                      options.c_cflag &= ~PARODD;
	                       options.c_iflag |= (INPCK | ISTRIP);
	                       break;
                case 'S':
                case 's':
                        	options.c_cflag &= ~PARENB;
                        	options.c_cflag &= ~CSTOPB;
                        	break;

                default:
                        	fprintf(stderr,"Unsupported parity!\n");
                        	return (1);
        }

	switch(baud)
	{
		case B9600:
				cfsetispeed(&options, B9600);
				cfsetospeed(&options, B9600);
				break;
		case B115200:
				cfsetispeed(&options, B115200);
				cfsetospeed(&options, B115200);
				break;
		default:
				cfsetispeed(&options, B115200);
				cfsetospeed(&options, B115200);
				break;
	}

        switch (stopbits)
        {
                case 1:
                        	options.c_cflag &= ~CSTOPB;	break;
                case 2:
                        	options.c_cflag |= CSTOPB; 	break;
                default:
                        	fprintf(stderr,"Unsupported stop bits ! \n");
                        	return (1);
        }
        options.c_cc[VMIN] = 0;
        options.c_cc[VTIME] = 0;

        tcflush(fd,TCIFLUSH);
        if ((tcsetattr(fd,TCSANOW,&options)) != 0)
        {
                perror("tcsetattr failed!\n");
                return (1);
        }
        return (0);
}


int console_fd;
static int login_with_console()
{
	struct vty * vty = NULL; 
	int ret = 0;

       console_fd = open(ZEBRA_CONSOLE, O_RDWR|O_NOCTTY|O_NONBLOCK);
       //console_fd = dup(0);
	if(console_fd > 0)
	{
		ret = uart_set_proper(console_fd, B115200, 8, 1, 'N');
		if(ret != 0)
			printf("return value of set uart proper: %d\n", ret);

	 	vty = PMC_vty_create (console_fd, NULL);
		printf("Create vty ......\n");
	}
	else
        {
              tcflush(console_fd, TCOFLUSH);
              printf("Can not dup %s \n", ZEBRA_CONSOLE);
		close(console_fd);
              return (1);
        }
	return 0;
}
#endif

/* Main startup routine. */
static int
CLI_mode_thread_func(void)
{
	while (TRUE)
	{
		char *vty_addr = NULL;
		short vty_port = ZEBRA_VTY_PORT;
		struct thread thread;

	   	/* Make vty server socket. */
        	if (alternative_port != 0) 
        	{
            		vty_port = alternative_port;
        	}
			
		PMC_vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH);

		global_thread = &thread;
		while (PMC_thread_fetch (zebrad.master, &thread))
		{
			PMC_thread_call (&thread);
			if (PMC_kill_all_vty)
				PMC_vty_kill_all();
		}
	}
    	/* Not reached... */
    	exit (0);
}

extern zlog_category_t *zc;
int CLI_activate()
{
  	char *config_file = NULL;

  	/* Make master thread emulator. */
  	zebrad.master = PMC_thread_master_create ();

  	/* Vty related initialize. */
  	PMC_cmd_init ();	
	log_init();
	
	General_cmd_init();	
	log_cmd_init();
	PMC_vty_init (zebrad.master);
  	/* Sort VTY commands. */
	PMC_sort_node ();
	language = 0;         /*language status*/
    	PMC_vty_config_password ();
	qh_zlog_info(zc, "cli active ...");
	return (CLI_mode_thread_func());	/* Running in Main function, you change running mode here! */
}

